package com.marinesky.web.common.csrf;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.util.WebUtils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.UUID;

/*
                   _ooOoo_
                  o8888888o
                  88" . "88
                  (| -_- |)
                  O\  =  /O
               ____/`---'\____
             .'  \\|     |//  `.
            /  \\|||  :  |||//  \
           /  _||||| -:- |||||-  \
           |   | \\\  -  /// |   |
           | \_|  ''\---/''  |   |
           \  .-\__  `-`  ___/-. /
         ___`. .'  /--.--\  `. . __
      ."" '<  `.___\_<|>_/___.'  >'"".
     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
     \  \ `-.   \_ __\ /__ _/   .-` /  /
======`-.____`-.___\_____/___.-`____.-'======
                   `=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         佛祖保佑       永无BUG
//          佛曰:
//                  写字楼里写字间，写字间里程序员；
//                  程序人员写程序，又拿程序换酒钱。
//                  酒醒只在网上坐，酒醉还来网下眠；
//                  酒醉酒醒日复日，网上网下年复年。
//                  但愿老死电脑间，不愿鞠躬老板前；
//                  奔驰宝马贵者趣，公交自行程序员。
//                  别人笑我忒疯癫，我笑自己命太贱；
//                  不见满街漂亮妹，哪个归得程序员？
/
                     Created by Marinesky on 2017/6/7.
 */
@Component
public class CookieCsrfTokenRepository implements CsrfTokenRepository {


    static final String DEFAULT_CSRF_COOKIE_NAME = "CSRF-TOKEN";

    static final String DEFAULT_CSRF_PARAMETER_NAME = "_csrf";

    static final String DEFAULT_CSRF_HEADER_NAME = "X-CSRF-TOKEN";

    private final Method setHttpOnlyMethod;

    private boolean cookieHttpOnly;

    private String cookiePath;



    public CookieCsrfTokenRepository() {
        this.setHttpOnlyMethod = ReflectionUtils.findMethod(Cookie.class, "setHttpOnly", boolean.class);
        if (this.setHttpOnlyMethod != null) {
            this.cookieHttpOnly = true;
        }
    }

    /**
     * 生成csrftoken
     *
     * @param request
     * @return
     */
    @Override
    public CsrfTokenEntity generateToken(HttpServletRequest request) {
        return new CsrfTokenEntity(DEFAULT_CSRF_HEADER_NAME,DEFAULT_CSRF_PARAMETER_NAME, UUID.randomUUID().toString());
    }

    /**
     * 保存token
     *
     * @param token
     * @param request
     * @param response
     */
    @Override
    public void saveToken(CsrfTokenEntity token, HttpServletRequest request, HttpServletResponse response) {
       saveCookieToken(token,request,response,-1);

    }

    /**
     * 删除token
     *
     * @param token
     * @param request
     * @param response
     */
    @Override
    public void deleteToken(CsrfTokenEntity token, HttpServletRequest request, HttpServletResponse response) {
        saveCookieToken(token,request,response,0);
    }


    /**
     *
     * @param token
     * @param request
     * @param response
     * @param secondMaxAge
     */
    private void saveCookieToken(CsrfTokenEntity token, HttpServletRequest request, HttpServletResponse response,int secondMaxAge){
        if(token==null) return;
        String tokenValue = token.getToken();
        Cookie cookie = new Cookie(DEFAULT_CSRF_COOKIE_NAME,tokenValue);
        cookie.setSecure(request.isSecure());

        if(StringUtils.isEmpty(cookiePath)){
            cookiePath = request.getContextPath();
            if(StringUtils.isEmpty(cookiePath)){
                cookiePath = "/";
            }

        }
        cookie.setPath(cookiePath);
        cookie.setMaxAge(secondMaxAge);
        if (cookieHttpOnly && setHttpOnlyMethod != null) {
            ReflectionUtils.invokeMethod(setHttpOnlyMethod, cookie, Boolean.TRUE);
        }

        response.addCookie(cookie);
    }

    /**
     * 加载token
     *
     * @param request
     * @return
     */
    @Override
    public CsrfTokenEntity loadToken(HttpServletRequest request) {
        Cookie cookie = WebUtils.getCookie(request,DEFAULT_CSRF_COOKIE_NAME);
        if (cookie == null) {
            return null;
        }
        String token = cookie.getValue();
        if (StringUtils.isEmpty(token)) {
            return null;
        }
        return new CsrfTokenEntity(DEFAULT_CSRF_HEADER_NAME,DEFAULT_CSRF_PARAMETER_NAME, token);
    }
}
